﻿/*-----------------------------------------------
// File: EngineCopyEnemyAI.cs
// Description: 
// Author: Shaobing	492057342@qq.com
-----------------------------------------------*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Battle.Engine.LogicModel;

namespace Battle.Engine.AI
{

    public class EngineCopyEnemyAI : EngineAI 
    {
        public enum CopyEnenyAIStep {
            None,
            Normal,
            Ultimate
        }
        
        protected EngineAIMsg curUltiMsg = null;
        public CopyEnenyAIStep curStep = CopyEnenyAIStep.None;
        EngineAIMsg curMsg = null;
        /// <summary>
        /// AI消息队列
        /// </summary>
        Queue<EngineAIMsg> msgQueue = new Queue<EngineAIMsg>();
        /// <summary>
        /// 正在执行的AI消息队列
        /// </summary>
        List<EngineAIMsg> dealedMsgs = new List<EngineAIMsg>();
        /// <summary>
        /// 大招AI消息队列
        /// </summary>
        Queue<EngineAIMsg> ultiMsgQueue = new Queue<EngineAIMsg>();

        public double CopyEnemyAIDeltaTime { get {
                return engine.data.tableDataUtil.GetCopyEnemyAIDeltaTime();
            }
        }

        public override void Start(EngineData data, CampType camp, BaseCompute engine)
        {
            base.Start(data, camp, engine);
            curStep = CopyEnenyAIStep.None;
            dealedMsgs = new List<EngineAIMsg>();
            ultiMsgQueue = new Queue<EngineAIMsg>();
            msgQueue = new Queue<EngineAIMsg>();
            curMsg = null;
        }

        public const string CopyEnemyGUIDPrefix = "enemy_copy_";
        public override void Run()
        {
            if (isRunning == true)
                return;
            isRunning = true;

            base.Run();
            dealedMsgs.Clear();
            ultiMsgQueue.Clear();
            msgQueue.Clear();
            curMsg = null;
            curUltiMsg = null;
            List<FActor> runActors = GetNormalSkillCastOrderActors();
            foreach (var actor in runActors)
            {
                if (actor.state == FActorState.DEAD || actor.state == FActorState.WAEKDEAD)
                {
                    continue;
                }
                if (actor.heroClass == (int)HeroClass.Hero || actor.heroClass == (int)HeroClass.Main_Actor_Man || actor.heroClass == (int)HeroClass.Main_Actor_Woman)
                {
                    var skill1 = actor.GetFSkill(0);
                    if (skill1 != null && actor.isCanDoSkill(skill1))
                    {
                        msgQueue.Enqueue(new EngineAIMsg(actor, skill1.index));
                    }
                    var skill2 = actor.GetFSkill(1);
                    if (skill2 != null && actor.isCanDoSkill(skill2))
                    {
                        msgQueue.Enqueue(new EngineAIMsg(actor, skill2.index));
                    }
                }
                else if (actor.heroClass == (int)HeroClass.Monster)
                {
                    if (isSkillCanCast(actor, 2))
                    {
                        actor.SetSkill(0, false);
                        actor.SetSkill(1, false);
                        ultiMsgQueue.Enqueue(new EngineAIMsg(actor, 2));
                    }
                    else {
                        if (isSkillCanCast(actor, 0) && isSkillCanCast(actor, 1))
                        {
                            if (data.random.value > GetCopyEnemyFirstSkillPercent(actor))
                            {
                                actor.SetSkill(0, true);
                                actor.SetSkill(1, false);
                                msgQueue.Enqueue(new EngineAIMsg(actor, 0));
                            }
                            else {
                                actor.SetSkill(0, false);
                                actor.SetSkill(1, true);
                                msgQueue.Enqueue(new EngineAIMsg(actor, 1));
                            }
                        }
                        else if (isSkillCanCast(actor, 0) && !isSkillCanCast(actor, 1))
                        {
                            actor.SetSkill(0, true);
                            msgQueue.Enqueue(new EngineAIMsg(actor, 0));
                        }
                        else if (!isSkillCanCast(actor, 0) && isSkillCanCast(actor, 1))
                        {
                            actor.SetSkill(1, true);
                            msgQueue.Enqueue(new EngineAIMsg(actor, 1));
                        }
                    }

                }
            }
            curStep = CopyEnenyAIStep.Normal;
            cdLeftTime = 0;
        }

        double GetCopyEnemyFirstSkillPercent(FActor actor) {
            if (actor.firstSkillCastChance > 0)
            {
                // 值有效返回概率
                return actor.firstSkillCastChance * 0.01f;
            }
            else {
                // 值无效返回默认值
                return 0.5f;
            }
        }

        bool isSkillCanCast(FActor actor, int index) {
            var skill = actor.GetFSkill(index);
            if (skill == null)
                return false;
            if (actor.isCanDoSkill(skill))
                return true;
            return false;
        }

        public override void StopRun()
        {
            base.StopRun();
            curStep = CopyEnenyAIStep.None;
            dealedMsgs.Clear();
        }

        double cdLeftTime;
        public override void Update(double deltaTime)
        {
            if (isRunning == false)
                return;
            if (curStep == CopyEnenyAIStep.Normal)
            {
                if (cdLeftTime > 0)
                {
                    cdLeftTime -= deltaTime; 
                    return;
                }
                if (curMsg == null)
                {
                    if (msgQueue.Count > 0)
                    {
                        curMsg = msgQueue.Dequeue();
                    }
                }
                if (curMsg != null)
                {
                    var skill = curMsg.skill;
                    switch (skill.state)
                    {
                        case FSkillState.None:
                            engine.DoSkill(curMsg.actor.player.camp, curMsg.actor.uniqueId, curMsg.skill.index);
                            dealedMsgs.Add(curMsg);
                            curMsg = null;
                            cdLeftTime = 1;
                            break;
                        default:
                            curMsg = null;
                            cdLeftTime = 1;
                            break;

                    }
                }
                if (IsAllNormalMsgDone()) {
                    curStep = CopyEnenyAIStep.Ultimate;
                    return;
                }
            }
            else if (curStep == CopyEnenyAIStep.Ultimate) {
                if (curUltiMsg == null) {
                    if (ultiMsgQueue.Count > 0)
                    {
                        curUltiMsg = ultiMsgQueue.Dequeue();
                    }
                    else {
                        var ultiActors = GetUltimateReadyActor(false);
                        if (ultiActors.Count > 0)
                        {
                            curUltiMsg = new EngineAIMsg(ultiActors[0], 2);
                        }
                        else {
                            if (data.compute.IsSkipping())
                            {
                                if (callback != null)
                                {
                                    callback.FinishRound();
                                }
                            }
                            else {
                                if (callback != null)
                                {
                                    callback.HaventActiveNormalSkill();
                                }
                            }
                        }
                    }
                }
                if (curUltiMsg != null) {
                    var skill = curUltiMsg.skill;
                    switch (skill.state) {
                        case FSkillState.None:
                            engine.DoSkill(curUltiMsg.actor.player.camp, curUltiMsg.actor.uniqueId, (int)SkillType.Ultimate);
                            break;
                        case FSkillState.FINISH:
                            curUltiMsg = null;
                            break;
                    }
                }
            }
        }

        bool IsAllNormalMsgDone() {
            if (msgQueue.Count != 0) {
                return false;
            }
            foreach (var msg in dealedMsgs) {
                if (msg.skill.state != FSkillState.FINISH) {
                    return false;
                }

            }
            return true;
        }

        public override void Stop()
        {
            base.Stop();
            curStep = CopyEnenyAIStep.None;
        }

        protected List<FActor> GetNormalSkillCastOrderActors()
        {
            Dictionary<int , List<FActor>> actorCaches = new Dictionary<int, List<FActor>>();
            List<int> actorTypes = new List<int>();
            foreach (var actor in player.actors) {
                if (actor.state == FActorState.DEAD || actor.state == FActorState.WAEKDEAD)
                    continue;
                if (actorCaches.ContainsKey(actor.aiProperty))
                {
                    actorCaches[actor.aiProperty].Add(actor);
                }
                else {
                    actorCaches.Add(actor.aiProperty, new List<FActor>());
                    actorCaches[actor.aiProperty].Add(actor);
                }
                if (!actorTypes.Contains(actor.aiProperty)) {
                    actorTypes.Add(actor.aiProperty);
                }
            }
            // 优先级大的先行动
            actorTypes.Sort(delegate (int a, int b) {
                return b.CompareTo(a);
            });
            foreach (var kvp in actorCaches)
            {
                kvp.Value.Sort(delegate (FActor a, FActor b) {
                    return a.MainPosition.ToFPID().CompareTo(b.MainPosition.ToFPID());
                });
            }
            List<FActor> actors = new List<FActor>();
            foreach (var actorType in actorTypes) {
                actors.AddRange(actorCaches[actorType]);
            }
            return actors;
            
        }


    }
}